//////////////////////////////////////////////////////////////////////////

#ifndef _RESEARCH_H_
#include "research.h"
#endif

//////////////////////////////////////////////////////////////////////////


Research::Research( const QString& _date, const ResultsTable& _resTable )
: m_Date(_date),
  m_Results(_resTable)
{
}


//////////////////////////////////////////////////////////////////////////


const QString& Research::GetDate() const
{
    return m_Date;
}


//////////////////////////////////////////////////////////////////////////


const ResultsTable& Research::GetResultsTable() const
{
    return m_Results;
}


//////////////////////////////////////////////////////////////////////////


void Research::AddData( unsigned char _data, size_t _count )
{
    // When signal is 0 then corresponding point on the floor
    bool rightHeelDown = (_data & 0x80) == 0;
    bool rightToeDown= (_data & 0x40) == 0;
    bool leftHeelDown = (_data & 0x20) == 0;
    bool leftToeDown = (_data & 0x10) == 0;
    size_t duration = _count;

    FeetPosition position = { rightHeelDown,
                              leftHeelDown,
                              rightToeDown,
                              leftToeDown,
                              duration };

    m_ResearchData.push_back(position);
}


//////////////////////////////////////////////////////////////////////////


void Research::Calculate()
{
    // Kill first and last step, because they are not full
    KillFirstStep();

    // Is first step begins from the left leg
    bool isLeftStep = IsLeftUp(0);

    size_t steps = 0;
    size_t position = 0;
    size_t lastPosition = 0;
    do 
    {
        for ( ++position; position < m_ResearchData.size(); position++ )
        {
            if ( isLeftStep && !IsLeftUp(position) )
                break;
            
            if ( !isLeftStep && !IsRightUp(position) )
                break;
        }

        for ( ++position; position < m_ResearchData.size(); position++ )
        {
            if ( isLeftStep && IsLeftUp(position) )
                break;

            if ( !isLeftStep && IsRightUp(position) )
                break;
        }

        if ( position < m_ResearchData.size() )
        {
            // Increment steps count
            ++steps;
            lastPosition = position;
        }
        else
        {
            m_ResearchData.erase( m_ResearchData.begin() + lastPosition,
                                  m_ResearchData.end() );
            break;
        }

    } while ( true );

    if (steps)
        CalculateTimes(steps);
}


//////////////////////////////////////////////////////////////////////////


void Research::KillFirstStep()
{
    bool isStepBegins = false;
    bool isLeftFirst = false;
    for (size_t position = 0; position < m_ResearchData.size(); position++)
    {
        bool isRightUp = IsRightUp(position);
        bool isLeftUp = IsLeftUp(position);
        if ( !(isRightUp ^ isLeftUp) )
            continue;

        if ( !isStepBegins )
        {
            isStepBegins = true;
            isLeftFirst = isLeftUp;
        }
        else
        {
            if (isLeftFirst && isRightUp || !isLeftFirst && isLeftUp)
            {
                m_ResearchData.erase( m_ResearchData.begin(),
                                      m_ResearchData.begin() + position );
                break;
            }
        }
    }
}


//////////////////////////////////////////////////////////////////////////


bool Research::IsRightUp( size_t _position ) const
{
    const FeetPosition& feetPosition = m_ResearchData[_position];
    return !feetPosition.m_RightHeelDown && !feetPosition.m_RightToeDown;
}


//////////////////////////////////////////////////////////////////////////


bool Research::IsLeftUp( size_t _position ) const
{
    const FeetPosition& feetPosition = m_ResearchData[_position];
    return !feetPosition.m_LeftHeelDown && !feetPosition.m_LeftToeDown;
}


//////////////////////////////////////////////////////////////////////////


void Research::CalculateTimes( size_t _steps )
{
    size_t totalTime = 0;
    for (size_t i = 0; i < m_ResearchData.size(); ++i)
    {
        size_t duration = m_ResearchData[i].m_Duration;
        
        m_Results.m_StepTime += duration;

        if (m_ResearchData[i].m_LeftHeelDown && m_ResearchData[i].m_LeftToeDown)
            m_Results.m_LeftFootDown += duration;
        else
            if (m_ResearchData[i].m_LeftHeelDown)
                m_Results.m_LeftHeelDown += duration;
            else
                if (m_ResearchData[i].m_LeftToeDown)
                    m_Results.m_LeftToeDown += duration;
                else
                    m_Results.m_LeftFootUp += duration;

        if (m_ResearchData[i].m_RightHeelDown && m_ResearchData[i].m_RightToeDown)
            m_Results.m_RightFootDown += duration;
        else
            if (m_ResearchData[i].m_RightHeelDown)
                m_Results.m_RightHeelDown += duration;
            else
                if (m_ResearchData[i].m_RightToeDown)
                    m_Results.m_RightToeDown += duration;
                else
                    m_Results.m_RightFootUp += duration;

        if ( !IsRightUp(i) && !IsLeftUp(i) )
            m_Results.m_DoubleSeatPhase += duration;

        totalTime += duration;
    }

    m_Results.m_StepTime /= (double)_steps;
    m_Results.m_LeftFootDown /= (double)_steps;
    m_Results.m_LeftHeelDown /= (double)_steps;
    m_Results.m_LeftToeDown /= (double)_steps;
    m_Results.m_LeftFootUp /= (double)_steps;
    m_Results.m_RightFootDown /= (double)_steps;
    m_Results.m_RightHeelDown /= (double)_steps;
    m_Results.m_RightToeDown /= (double)_steps;
    m_Results.m_RightFootUp /= (double)_steps;
    m_Results.m_DoubleSeatPhase /= (double)_steps;
    m_Results.m_RythmCoefficient = std::min(m_Results.m_RightFootUp, m_Results.m_LeftFootUp) 
                                 / std::max(m_Results.m_RightFootUp, m_Results.m_LeftFootUp);

}


//////////////////////////////////////////////////////////////////////////
